package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"
	"test/imp"
	"time"
	"test/model"
)

func addUpper() func (int) int {
	n := 10
	str := "hello"
	return func (x int) int{
		n += x
		str += string(x)
		fmt.Println("str=",str)
		return n
	}
}
func makeSuffix(suffix string) func (string) string {
	return func (s string) string{
		bool := strings.HasSuffix(s,suffix)
		if bool {
			return s
		}else{
			return s + suffix
		}
	}
}

func fbn(n int)([]uint64){
	//声明切片
	fbnSlice := make([]uint64,n)
	fbnSlice[0] = 1
	fbnSlice[1] = 1
	for i := 2 ;i < n; i++{
		fbnSlice[i] = fbnSlice[i-1] + fbnSlice[i-2]
	}
	return fbnSlice
}

//二分查找
func BinaryFind(arr *[7]int ,leftIndex int,rightIndex int,findVal int){
	//判断leftIndex 是否大于 rightIndex
	if(leftIndex > rightIndex){
		fmt.Println("找不到该数字")
		return
	}
	//先找中间下标
	//middle := int(math.Ceil(float64((leftIndex + rightIndex) / 2)))
	middle := (leftIndex + rightIndex) / 2
	if (*arr)[middle] > findVal{
		//说明查找的数应该在 leftIndex --- middle-1
		BinaryFind(arr,leftIndex,middle - 1,findVal)
	}else if (*arr)[middle] < findVal{
		//说明查找的数应该再 middle + 1 --- rightIndex
		BinaryFind(arr,middle + 1,rightIndex,findVal)
	}else{
		//找到了
		fmt.Printf("找到了，下标为%v\n",middle)
	}
}

//二分查找1
func BinaryFinds(arr *[10]int ,leftIndex int,rightIndex int,findVal int){
	//判断leftIndex 是否大于 rightIndex
	if(leftIndex > rightIndex){
		fmt.Println("找不到该数字")
		return
	}
	//先找中间下标
	//middle := int(math.Ceil(float64((leftIndex + rightIndex) / 2)))
	middle := (leftIndex + rightIndex) / 2
	if (*arr)[middle] > findVal{
		//说明查找的数应该在 leftIndex --- middle-1
		BinaryFinds(arr,leftIndex,middle - 1,findVal)
	}else if (*arr)[middle] < findVal{
		//说明查找的数应该再 middle + 1 --- rightIndex
		BinaryFinds(arr,middle + 1,rightIndex,findVal)
	}else{
		//找到了
		fmt.Printf("找到了，下标为%v\n",middle)
	}
}

//测试方法
func test1(){
	var arrays [10]int
	avgs := 0
	sums := 0
	length := len(arrays) - 1
	count := len(arrays)
	rand.Seed(time.Now().UnixNano())
	for i := 0;i < count; i++{
		arrays[i] = rand.Intn(100 )
		sums += arrays[i]
	}
	avgs = sums / count
	for j := count - 1;j >= 0;j--{
		fmt.Printf("arrays[%d]当前值:%v\n",j,arrays[j])
	}
	fmt.Printf("当前平均值是：%d\n",avgs)
	var tmp int
	for i := 0;i < length; i++{
		for j := 0;j < length - i;j++{
			after := j + 1
			tmp = arrays[j]
			if arrays[after] < tmp && (after <= length){
				arrays[j] = arrays[after]
				arrays[after] = tmp
			}
		}
	} 
	fmt.Println("排序后数组为：",arrays)
	fmt.Printf("数组最大值下标为%d,最大值为%d\n",length,arrays[length])
	BinaryFinds(&arrays,0,10,55)
}

//声明结构体
type Person struct{
	Name int
	Sex int
	num1 float64
	num2 float64
}

//继承实现 学生结构体继承了Person结构体
type Student struct{
	Person //嵌套person结构体，实现继承person结构体的相关内容
	c Circle //嵌套Circle结构体
	Age int8
	Stature int8
}

//引用类型的取值
type Student2 struct{
	*Person //嵌套person结构体，实现继承person结构体的相关内容
	*Circle //嵌套Circle结构体
	int //也可以直接嵌套默认数据类型
}

//给结构体绑定方法
/**
注意：此处为值传递，无论外部调用是否是值传递，都用值传递处理，反之亦然

*/
func (p Person) getSum(n1 int,n2 int) int{
	p.num1 = 5 //此处因为是值传递，如果外部是引用传递，不会改变结构体里面num1的值
	return n1 + n2
}
//给Person 实现方法String()
func (p *Person) String() string{
	str := fmt.Sprintf("Name=[%v] Age=[%v]",p.Name,p.Sex) //数据格式化
	return str
}

//计算小数
/**
 	注意：此处为引用传递，无论外部调用是否是引用传递，都已引用传递处理，反之亦然

 */
func (p *Person) sum(n1 float64,n2 float64) float64{
	p.num1 = 5 //此处因为是引用传递，如果外部是值传递，依然会改变结构体里面num1的值
	return n1 + n2
}

//实现计算形式（switch）
func (p *Person) getRes(operator byte) float64{
	res := 0.0
	switch operator {
		case '*':
			res = p.num1 * p.num2
		case '/':
			res = p.num1 / p.num2
		case '+':
			res = p.num1 + p.num2
		case '-':
			res = p.num1 - p.num2
		default :
			fmt.Println("运算符输入有误！")
	}
	return res
}

//声明一个圆形结构体
type Circle struct{
	radius float64
}

//给圆形结构体绑定方法计算面积
func (c Circle) area() float64{
	return 3.14 * c.radius * c.radius
}

//给数据类型绑定方法
type integer int

/**
	1.方法名首字母大写可以跨包使用，小写只能在本包使用
	2.变量同上
 */
func( i integer) print(){
	fmt.Println("i=",i)
}

//声明一个接口
type Usb interface{
	Start() int //定义接口方法 后面int代表返回值
	Stop()
}

//定义一个结构体继承接口
type Phone struct{

}

//让Phone 实现Usb接口的方法  ※必须实现接口的所有方法。
func (p Phone) Start() int {
	fmt.Println("手机开始工作。。。")
	return 111
}
func (p Phone) Stop() {
	fmt.Println("手机停止工作。。。")
}

//计算机实现Usb接口方法
type Computer struct{

}

//编写一个方法Working ，接受一个Usb接口类型变量
//只要实现了Usb接口 （实现了Usb接口的所有方法）
func (c Computer) Working(usb Usb){
	//通过usb接口变量来执行方法
	usb.Start()
	usb.Stop()
}

//接口继承
type Ainterface interface{
	test01()
}

type Binterface interface{
	test02()
}

//C接口继承了AB接口 需要同时实现 A，B ，C接口的方法才可以使用C接口
//继承接口里面不允许有同名函数，否则报错。
type Cinterface interface{
	Ainterface
	Binterface
	test03()
}

//实现C接口
type test struct{

}
//结构体实现接口方法传参类型要和赋值类型一致，指针类型则传指针变量，值类型传值变量，否者不算作实现接口方法，调用时则会报错
//        ↓
func (t test) test01(){
	fmt.Println("test01()")
}

func (t test) test02(){
	fmt.Println("test02()")
}

func (t test) test03(){
	fmt.Println("test03()")
}

func(t test) NewWoring(C Cinterface){
	C.test03()
}

type T interface{

}

//检测传进来的值的类型状态
func TypeJudge(items ...interface{}){
	for i,x := range items {
		switch x.(type){//type是一个关键字，固定写法
			case bool:
				fmt.Printf("param #%d is a bool 值是%v \n",i,x)
			case float32:
				fmt.Printf("param #%d is a float32 值是%v \n",i,x)
			case float64:
				fmt.Printf("param #%d is a float64 值是%v \n",i,x)
			case int,int32,int64:
				fmt.Printf("param #%d is an int 值是%v \n",i,x)
			case nil:
				fmt.Printf("param #%d is nil 值是%v \n",i,x)
			case string:
				fmt.Printf("param #%d is string 值是%v \n",i,x)
			case Person:
				fmt.Printf("param #%d is Person 值是%v \n",i,x)
			case *Person:
				fmt.Printf("param #%d is *Person 值是%v \n",i,x)
			default:
				fmt.Printf("param #%d is unknown 值是%v \n",i,x)
		}
	}
}

func main() {
	var s = 500
	fmt.Println(strconv.FormatInt(int64(s), 10))
	var str = "11113423"
	var n1 int64
	n1, _ = strconv.ParseInt(str, 0, 0)
	fmt.Printf("n1 type %T\n", n1)
	fmt.Println("n1=", n1)
	fmt.Println(imp.Tt)
	var hs float32 = 136.2
	var ss float32 = 5.0 / 9 * (hs - 100)
	fmt.Printf("%v对应的摄氏温度为:%v \n", hs, ss)
	n2 := 1
	n3 := 0
	if n3 > 0 || n2 == 2 {
		fmt.Println("true")
	} else {
		fmt.Println("false")
	}
	f := addUpper()
	fmt.Println(f(1))
	fun := makeSuffix(".def")
	fmt.Println(fun("test1.def"))
	now := time.Now()
	fmt.Printf(now.Format("2006-01-02 15:04:05"))
	var array [26]byte
	for i := 0; i < 26; i++ {
		array[i] = 'A' + byte(i)
		fmt.Printf("当前是第%d,值是%c\n", i, array[i])
	}
	var slice = make([]int, 6, 12)
	fmt.Println(slice)
	var strSlice []string = []string{"tom", "jack", "jerry"}
	fmt.Println(strSlice)
	slice2 := strSlice[1:2]
	fmt.Println(slice2)
	var slice3 []int = []int{100, 200, 300}
	slice3 = append(slice3, 400, 500)
	fmt.Println("slice3", slice3)
	var slice4 []int = []int{1, 2, 3, 4, 5}
	var slice5 = make([]int, 10)
	copy(slice5, slice4)
	fmt.Println("slice5", slice5)

	//string 英文+数字
	str1 := "hello@world"
	slice6 := []byte(str1)
	slice6[0] = 'c'
	str1 = string(slice6)
	fmt.Println("str=", str1)

	//string 中文处理
	str2 := "北京时代广场"
	arr2 := []rune(str2)
	arr2[3] = '生'
	str2 = string(arr2)
	fmt.Println("str2=", str2)
	fbnSlice := fbn(10)
	fmt.Println(fbnSlice)

	//顺序查找
	names := [4]string{"西海龙王", "东海龙王", "北海龙王", "南海龙王"}
	var findName = ""
	fmt.Println("请输入要查找的人名\n")
	fmt.Scanln(&findName)
	for i := 0; i < len(names); i++ {
		if findName == names[i] {
			fmt.Printf("找到%v,下标%v\n", findName, i)
			break
		} else if i == (len(names) - 1) {
			fmt.Printf("没有找到%v\n", findName)
		}
	}

	//二分查找
	findArr := [7]int{1, 10, 50, 100, 500, 1000, 1234}
	findNum := 0
	fmt.Println("请输入要查找的数字")
	fmt.Scanln(&findNum)
	BinaryFind(&findArr, 0, len(findArr)-1, findNum)

	//定义二维数组
	var arr [4][6]int

	fmt.Println(arr)
	var arr3 [2][3]int = [2][3]int{{1, 2, 3}, {4, 5, 6}}
	fmt.Println(arr3)
	//求平均分
	scores := [3][5]float64{{1, 1, 1, 1, 1}, {2, 2, 2, 2, 2}, {3, 3, 3, 3, 3}}
	for i, v := range scores {
		sum := 0.0
		for _, vs := range v {
			sum += vs
		}
		fmt.Printf("第%d个班级的平均分为%.2f\n", i+1, sum/float64(len(v)))
	}

	//测试题
	test1()
	//声明map 第一种方式
	cities := make(map[string]string)
	cities["no1"] = "北京"
	cities["no2"] = "武汉"
	fmt.Println(cities)
	//声明map 第二种方式
	heroes := map[string]string{
		"突然":  "test1",
		"sss": "顶顶顶顶",
	}
	heroes["啊啊啊"] = "少时诵诗书"
	fmt.Println("heroes=", heroes)

	//map 使用方案
	studentMap := make(map[string]map[string]string)
	studentMap["stu01"] = make(map[string]string, 2)
	studentMap["stu01"]["name"] = "tom"
	studentMap["stu01"]["sex"] = "male"
	studentMap["stu02"] = make(map[string]string, 2)
	studentMap["stu02"]["name"] = "tom"
	studentMap["stu02"]["sex"] = "female"
	fmt.Println("学生map", studentMap)

	//删除map
	delete(studentMap, "stu02")
	fmt.Println("删除后的map", studentMap)

	//map查找
	val,ok := cities["no3"]
	if ok {
		fmt.Printf("有no1 值为%v\n",val)
	}else{
		fmt.Println("没有no1值！")
	}

	//一次性删除map
	studentMap = make(map[string]map[string]string)
	fmt.Println("清空后的map",studentMap)

	//map切片
	var monsters []map[string]string
	monsters = make([]map[string]string,2)
	//新增内容
	if monsters[0] == nil{
		monsters[0] = make(map[string]string)
		monsters[0]["name"] = "孙悟空"
		monsters[0]["age"] = "500"
	}
	monsters[0]["sex"] = "男"
	monsters[1] = make(map[string]string)
	monsters[1]["name"] = "牛魔王"
	monsters[1]["age"] = "1000"
	//这里需要使用切片的append函数，动态增加
	//1.先定义monster信息
	monster := map[string]string{
		"name"	:	"红孩儿",
		"age"	:	"200",
	}
	monsters = append(monsters,monster)
	fmt.Println(monsters)

	//测试结构体
	person := Person{1,3,6,12}
	//使用结构体绑定方法
	fmt.Println(person.getSum(person.Name,person.Sex))

	//调用计算圆面积方法
	var c Circle
	c.radius = 4.0
	res := c.area()
	fmt.Println("圆形面积是=",res)
	//测试给数据类型绑定的方法
	var in integer = 10
	in.print()
	//如果实现了方法的String 方法。打印时默认调用
	//结构体创建方式1
	per := Person{
		Name:333,
		Sex:2,
		num1:5,
		num2:10}
	//结构体创建方式2
	var pe = &Person{2,3,1,5}
	fmt.Println(pe)
	fmt.Println(&per)
	fmt.Printf("结果是：%v\n",fmt.Sprintf("%.2f",per.sum(1.2,2.4))) //格式化2位小数
	fmt.Printf("结果是：%v \n",fmt.Sprintf("%.2f",per.getRes('/')))
	//循环输入
	for {
		fmt.Println("请输入内容")
		fmt.Scanln(&per.Name)
		if per.Name == 1314 {
			fmt.Println("退出程序")
			break
		}
	}

	//引用model下的结构体
	var st = model.NewStudent("tom",14)
	fmt.Println(st.GetName())

	/**
		继承部分
	 */
	//嵌入结构体之后的使用方法
	pupil := &Student{}
	//嵌套的匿名结构体的赋值方法
	pupil.Person.Name = 123
	//同时也可以这么访问
	pupil.Name = 145 //简写，直接访问
	pupil.Person.Sex = 11
	pupil.Sex = 15 //简写，直接访问
	//嵌套匿名方法里面的方法名和变量无论大小写都可以直接调用
	pupil.Person.num1 = 13
	//嵌套匿名结构体方法使用
	//如果有2个以上匿名结构体有相同的方法，则用指定匿名变量调用相应的方法（如果不指定，则用就近原则）
	re := pupil.Person.getSum(pupil.Person.Name,pupil.Person.Sex)
	ress := pupil.getSum(pupil.Name,pupil.Sex) //简写方式
	//嵌套第二个结构体的使用
	pupil.c.radius = 3.3 //如果不是匿名，有名称必须带上名称，否则会报错
	area := pupil.c.area()
	fmt.Println(pupil,re,pupil.Person.num1,ress,area)
	//嵌套后可以直接一次性赋值
	tests := Student{Person{11,22,33,44},Circle{2.3},12,122}
	fmt.Println(tests)
	//引用类型的取值
	stu3 := Student2{&Person{11,22,33,44},&Circle{2.3},20}
	//fmt.Println("stu2=",*stu3.Person,*stu3.Circle) //通过取值符获取相应内容
	fmt.Println("stu3",stu3)

	//测试接口部分内容
	computer := Computer{}
	phone := Phone{}
	//调用方法
	computer.Working(phone)

	//接口继承测试
	var t test
	var te Cinterface = t
	te.test03()

	//任何数据类型都实现了空接口，所以所有的数据类型都可以赋值给空接口
	var D T = t
	//第二种写法
	var D2 interface{} = t
	fmt.Println(D,D2)

	//类型断言(带检测)
	var a1 interface{} //空接口（可以接收任何值）
	var person1 = Person{1,2,3,4}
	a1 = person1
	var b1 Person
	//不可直接赋值
	//b1 = a1
	b1 = a1.(Person) //类型断言，测试a1可不可以转换成Person结构体然后赋值
	fmt.Println(b1)
	var a2 interface{}
	var b2 float32 = 1.1
	a2 = b2
	//y,flag := a2.(float32) //检测失败则判断 第一种写法
	if y,flag := a2.(float32); flag { //第二种写法
		fmt.Println("convert true")
		fmt.Printf("y 值类型是 %T，值是=%v",y,y)
	}else{
		fmt.Println("convert fail")
	}

	//检测函数的使用
	var v1 float32 = 1.1
	var v2 float64 = 2.3
	var v3 int32 = 30
	var v4 string = "jerry"
	v5 := "smith"
	v6 := 300
	v7 := Person{1,2,3,4}
	v8 := &Person{1,2,3,4}
	TypeJudge(v1,v2,v3,v4,v5,v6,v7,v8)

}